﻿#region copyright
//<copyright>
// Copyright(C) 2012 TrackerRealm Corporation
// This file is part of the open source project - Jazz. http://jazz.codeplex.com
// 
// Jazz is open software: you can redistribute it and/or modify it 
// under the terms of the GNU Affero General Public License (AGPL) as published by 
// the Free Software Foundation, version 3 of the License.
// 
// Jazz is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty 
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
//  See the GNU Affero General Public License (AGPL) for more details.
// 
// You should have received a copy of the GNU General Public 
// License along with Jazz.  If not, see <http://www.gnu.org/licenses/>.
//
// REMOVAL OF THIS NOTICE IS VIOLATION OF THE COPYRIGHT. 
//</copyright>
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using TrackerRealm.Jazz.Common;
using C = TrackerRealm.Jazz.Common.JazzConstants;

namespace TrackerRealm.Jazz.Client.Custom
{
    /// <summary>
    /// '<see cref="jUser"/>' describes a user. 
    /// <para>Users may have multiple profiles (see <see cref="jProfile"/>).
    /// </para> The roles for
    /// a user are contained a '<see cref="jProfile"/>' object.
    /// A user object always has a single default profile.
    /// <para>Typically the '<see cref="jUser"/>' class is used as a base class
    /// with more information about provided about the user in an inherited class.</para>
    /// <para>Need a custom jUser? - then clone, modify and own - </para>
    /// </summary>
    [Root]
    [Jazz]
    [UseEmptyObjectFor(typeof(jUserBase))]
    public sealed class jUser : jUserBase
    {
        #region GuestID
        /// <summary>
        /// The ID for the 'Guest' user.
        /// </summary>
        public static readonly Guid GuestID = new Guid("80ED57F3-D783-435B-A8F9-E4890DE46B99");
        #endregion
        #region EmptyID
        /// <summary>
        /// The ID for the 'empty' user.
        /// </summary>
        public static readonly Guid EmptyID = new Guid("132B1FE9-9680-4B6C-BAEF-BCDC27851629");
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public readonly new  static jUser[] EmptyArray = new jUser[0];
        //
        //Factory Methods - Create
        //
        #region CreateEmpty()
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static jUser CreateEmpty()
        {
            jUser user = new jUser(C.EMPTY); // C.EMPTY, jRole.EmptyArray);
            jProfile.Create(null, C.EMPTY, user, jRole.EmptyArray);
            return user;
        }
        #endregion
        #region Create(string name)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static jUser Create(string name)
        {
            return jUser.Create(name, jRole.EmptyArray);
        }
        #endregion
        #region Create(string name, params string[] roles)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="roles"></param>
        /// <returns></returns>
        public static jUser Create(string name, params string[] roles)
        {
            return jUser.Create(name, roles.Select(r =>jRole.Create(r)));
        }
        #endregion
        #region Create(string name, Roles roles)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="roles"></param>
        /// <returns></returns>
        public static jUser Create(string name, IEnumerable<jRole> roles)
        {
            jUser user = new jUser(name);
            jProfile.Create(null, "", user, roles);
            return user;
        }
        #endregion

        #region Create(ClientNexus nexus, string name)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="nexus"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static jUser Create(ClientNexus nexus, string name)
        {
            return jUser.Create(nexus, name, jRole.EmptyArray);
        }
        #endregion
        #region Create(ClientNexus nexus, string name, params string[] roles)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="nexus"></param>
        /// <param name="name"></param>
        /// <param name="roles"></param>
        /// <returns></returns>
        public static jUser Create(ClientNexus nexus, string name, params string[] roles)
        {
            return jUser.Create(nexus, name, roles.Select<string, jRole>(s => jRole.Create(nexus, s)));
        }
        #endregion
        #region Create(ClientNexus nexus, string name, Roles roles)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="nexus"></param>
        /// <param name="name"></param>
        /// <param name="roles"></param>
        /// <returns></returns>
        public static jUser Create(ClientNexus nexus, string name, IEnumerable<jRole> roles)
        {
            return new jUser(nexus, name, roles);
        }
        #endregion
        //
        // Constructors
        //
        #region Constructor
        /// <summary>
        /// Constructor - does not create a profile
        /// </summary>
        /// <param name="name"></param>
        private jUser(string name)
        :base(name)
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="nexus"></param>
        /// <param name="name"></param>
        /// <param name="roles"></param>
        private jUser(ClientNexus nexus, string name, IEnumerable<jRole> roles)
            : base(name) // don't pass the nexus - delay binding
        {
            this._Profile = jProfile.Create(nexus, "", this, roles);
            if (nexus != null)
            {
                nexus.Bind(this);
                nexus.Bind(this._Profile);
            }
        }
        #endregion
        #region Profiles
        /// <summary>
        /// 
        /// </summary>
        public IEnumerable<jProfile> Profiles
        {
            get { return base._Profiles.Cast<jProfile>(); }
        }
        #endregion Profile
        #region Profile
        /// <summary>
        /// Returns the default profile for the user.
        /// </summary>
        public jProfile Profile
        {
            get { return (jProfile)base._Profile; }
            set { base._Profile = value; }
        }
        #endregion
        #region Add/Remove profiles
        /// <summary>
        /// 
        /// </summary>
        /// <param name="profile"></param>
        public void AddProfile(jProfile profile)
        {
            base._AddProfile(profile);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="profile"></param>
        public void RemoveProfile(jProfile profile)
        {
            base._RemoveProfile(profile);
        }
        #endregion
        #region Assign Fixed Ids.
        /// <summary>
        /// Assigns a fixed ID to the 'Guest' user.
        /// </summary>
        /// <returns></returns>
        protected internal override Guid OnAssignID()
        {
            if (this.Name == C.GUEST) 
                return jUser.GuestID;
            else if (this.Name == C.EMPTY)
                return jUser.EmptyID;
            else
                return base.OnAssignID();
        }
        #endregion

        #region ACL -Add/Remove
        /// <summary>
        /// The ACL (Access Control List) controls how this '<see cref="jObject"/>' instance
        /// can be accessed.
        /// <para>Note: If the ACL sequence is empty then there are no access restrictions.</para>
        /// </summary>
        public IEnumerable<jAclItem> ACL
        {
            get { return base._ACL; }
        }
        /// <summary>
        /// Add a '<see cref="jAclItem"/>' to this jObject's ACL.
        /// </summary>
        /// <param name="item"></param>
        public void Add(jAclItem item)
        {
            base._Add(item);
        }
        /// <summary>
        /// Remove a '<see cref="jAclItem"/>' from this jObject's ACL.
        /// </summary>
        /// <param name="item"></param>
        public void Remove(jAclItem item)
        {
            base._Remove(item);
        }
        #endregion
        // Casting
        #region cast to jProfile
        /// <summary>
        /// Allows a '<see cref="jUser"/>' instance to be 
        /// implicitly cast (no cast operator) to a '<see cref="jProfile"/>' instance.
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static implicit operator jProfile (jUser user)
        {
            return (jProfile)user.Profile;
        }
        #endregion
        #region cast to jUser
        /// <summary>
        /// Allows a '<see cref="jProfile"/>' instance to be 
        /// implicitly cast (no cast operator) to a '<see cref="jUser"/>' instance.
        /// </summary>
        /// <param name="profile"></param>
        /// <returns></returns>
        public static implicit operator jUser(jProfile profile)
        {
            return (jUser)profile.User;
        }
        #endregion
    }
}
